/*
 * jxSwing Project (2014)
 * 
 * by Denilson Edinaldo Pinto
 * 
 * LGPL
 * Copyright (C) 2014
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
package org.jxSwing.component.label;

import java.awt.Color;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.util.Currency;
import java.util.Locale;

import javax.swing.JLabel;
import javax.swing.SwingConstants;

/**
 * @author Denilson Edinaldo Pinto
 * @porject jxSwing
 * @package org.jxSwing.component.label
 * @date 27/09/2014 - 11:26:06
 */
public class NumberLabel extends JLabel {
	
	private static final long serialVersionUID = -7921402967548489628L;
	
	private static final Color DEFAULT_FOREGROUND = new JLabel().getForeground();
	
	private final DecimalFormat decimalFormat;
	
	private char decimalSeparator;
	
	private boolean acceptDecimal;
	
	private int decimalDigits;
	
	private boolean money = false;
	
	/**
	 * decimal is true
	 */
	public NumberLabel() {
	
		this(false);
	}
	
	/**
	 * @param acceptDecimal
	 */
	public NumberLabel(final boolean acceptDecimal) {
	
		this(acceptDecimal, false);
	}
	
	/**
	 * @param acceptDecimal
	 * @param money
	 */
	public NumberLabel(final boolean acceptDecimal, final boolean money) {
	
		this(acceptDecimal, Locale.getDefault(Locale.Category.FORMAT), money);
	}
	
	/**
	 * @param acceptDecimal
	 * @param decimalDigits
	 */
	public NumberLabel(final boolean acceptDecimal, final int decimalDigits) {
	
		this(acceptDecimal, decimalDigits, Locale.getDefault(Locale.Category.FORMAT));
	}
	
	/**
	 * @param acceptDecimal
	 * @param decimalDigits
	 * @param money
	 */
	public NumberLabel(final boolean acceptDecimal, final int decimalDigits, final boolean money) {
	
		this(acceptDecimal, decimalDigits, Locale.getDefault(Locale.Category.FORMAT), money);
	}
	
	/**
	 * @param acceptDecimal
	 * @param decimalDigits
	 * @param locale
	 */
	public NumberLabel(final boolean acceptDecimal, final int decimalDigits, final Locale locale) {
	
		this(acceptDecimal, decimalDigits, locale, false);
	}
	
	/**
	 * @param acceptDecimal
	 * @param decimalDigits
	 * @param locale
	 * @param money
	 */
	public NumberLabel(final boolean acceptDecimal, final int decimalDigits, final Locale locale, final boolean money) {
	
		this.acceptDecimal = acceptDecimal;
		this.decimalDigits = decimalDigits;
		decimalFormat = new DecimalFormat();
		
		decimalFormat.setDecimalFormatSymbols(new DecimalFormatSymbols(locale));
		
		decimalSeparator = decimalFormat.getDecimalFormatSymbols().getDecimalSeparator();
		this.money = money;
		
		initGUI();
	}
	
	/**
	 * @param acceptDecimal
	 * @param locale
	 */
	public NumberLabel(final boolean acceptDecimal, final Locale locale) {
	
		this(acceptDecimal, locale, false);
	}
	
	/**
	 * @param acceptDecimal
	 * @param locale
	 * @param money
	 */
	public NumberLabel(final boolean acceptDecimal, final Locale locale, final boolean money) {
	
		this.acceptDecimal = acceptDecimal;
		decimalFormat = new DecimalFormat();
		
		decimalFormat.setDecimalFormatSymbols(new DecimalFormatSymbols(locale));
		
		decimalDigits = money ? decimalFormat.getCurrency().getDefaultFractionDigits() : 0;
		decimalSeparator = decimalFormat.getDecimalFormatSymbols().getDecimalSeparator();
		this.money = money;
		
		initGUI();
	}
	
	/**
	 * @param acceptDecimal
	 * @param currency
	 */
	public NumberLabel(final Currency currency) {
	
		decimalFormat = new DecimalFormat();
		
		decimalFormat.setCurrency(currency);
		
		acceptDecimal = currency.getDefaultFractionDigits() > 0;
		decimalDigits = currency.getDefaultFractionDigits();
		decimalSeparator = decimalFormat.getDecimalFormatSymbols().getDecimalSeparator();
		money = true;
		
		initGUI();
	}
	
	/**
	 * 
	 */
	private void initGUI() {
	
		setText(getSymbol() + "0");
		setHorizontalAlignment(SwingConstants.RIGHT);
	}
	
	/**
	 * @return the BigDecimal value
	 */
	public final BigDecimal getBigDecimalValue() {
	
		return BigDecimal.valueOf(getDoubleValue());
	}
	
	/**
	 * @return the BigInteger value
	 */
	public final BigInteger getBigIntegerValue() {
	
		return BigInteger.valueOf(getLongValue());
	}
	
	/**
	 * @return the currency
	 */
	public final Currency getCurrency() {
	
		return getFormat().getCurrency();
	}
	
	/**
	 * @return the decimalDigits
	 */
	public final int getDecimalDigits() {
	
		return decimalDigits;
	}
	
	/**
	 * @return the decimalSeparator
	 */
	public final char getDecimalSeparator() {
	
		return decimalSeparator;
	}
	
	/**
	 * @return the double value
	 */
	public final Double getDoubleValue() {
	
		final String value = getValue().trim();
		
		final String valueAux = value.replace(".", "").replace("-", "").trim();
		
		return valueAux.isEmpty() ? 0.00 : Double.parseDouble(value);
	}
	
	/**
	 * @return the float value
	 */
	public final Float getFloatValue() {
	
		return getDoubleValue().floatValue();
	}
	
	/**
	 * @return the decimal format
	 */
	public DecimalFormat getFormat() {
	
		return decimalFormat;
	}
	
	/**
	 * @return the int value
	 */
	public final Integer getIntValue() {
	
		return getDoubleValue().intValue();
	}
	
	/**
	 * @return the long value
	 */
	public final Long getLongValue() {
	
		return getDoubleValue().longValue();
	}
	
	/**
	 * @return the short value
	 */
	public final Short getShortValue() {
	
		return getDoubleValue().shortValue();
	}
	
	/**
	 * @return the currency symbol
	 */
	public final String getSymbol() {
	
		return isMoney() ? getCurrency().getSymbol() : "";
	}
	
	/**
	 * @return the number in String
	 */
	public String getValue() {
	
		return getText().trim().replace(getSymbol(), "").replace(String.valueOf(decimalSeparator), ".");
	}
	
	/**
	 * @return the acceptDecimal
	 */
	public final boolean isAcceptDecimal() {
	
		return acceptDecimal;
	}
	
	/**
	 * @return is money
	 */
	public boolean isMoney() {
	
		return money;
	}
	
	/**
	 * @param acceptDecimal
	 *        the acceptDecimal to set
	 */
	public final void setAcceptDecimal(final boolean acceptDecimal) {
	
		this.acceptDecimal = acceptDecimal;
	}
	
	/**
	 * @param decimalDigits
	 *        the decimalDigits to set
	 */
	public final void setDecimalDigits(final int decimalDigits) {
	
		this.decimalDigits = decimalDigits < 0 ? 0 : decimalDigits;
		
		acceptDecimal = decimalDigits > 0;
	}
	
	/**
	 * @param decimalSeparator
	 *        the decimalSeparator to set
	 */
	public final void setDecimalSeparator(final char decimalSeparator) {
	
		this.decimalSeparator = decimalSeparator;
	}
	
	/**
	 * @param money
	 */
	public void setMoney(final boolean money) {
	
		this.money = money;
		
		setDecimalDigits(money ? decimalFormat.getCurrency().getDefaultFractionDigits() : 0);
		setAcceptDecimal(getDecimalDigits() > 0);
		setValue(getBigDecimalValue());
	}
	
	/*
	 * (non-Javadoc)
	 * 
	 * @see javax.swing.text.JTextComponent#setText(java.lang.String)
	 */
	@Override
	public void setText(final String text) {
	
		super.setText(getSymbol() + text.replace(".", String.valueOf(decimalSeparator)));
		
		setForeground(getIntValue() < 0 ? Color.RED : DEFAULT_FOREGROUND);
	}
	
	/**
	 * @param value
	 */
	public void setValue(final BigDecimal value) {
	
		final BigDecimal roundValue = value.setScale(decimalDigits, BigDecimal.ROUND_HALF_UP);
		
		setText(getSymbol() + roundValue.toPlainString());
	}
	
	/**
	 * @param value
	 */
	public void setValue(final BigInteger value) {
	
		setText(getSymbol() + value);
	}
	
	/**
	 * @param value
	 */
	public void setValue(final Double value) {
	
		setValue(new BigDecimal(value));
	}
	
	/**
	 * @param value
	 */
	public void setValue(final Float value) {
	
		setValue(new BigDecimal(value));
	}
	
	/**
	 * @param value
	 */
	public void setValue(final Integer value) {
	
		setText(getSymbol() + value);
	}
	
	/**
	 * @param value
	 */
	public void setValue(final Long value) {
	
		setText(getSymbol() + value);
	}
	
	/**
	 * @param value
	 */
	public void setValue(final Short value) {
	
		setText(getSymbol() + value);
	}
	
	/**
	 * @param value
	 */
	public void subtract(final BigDecimal value) {
	
		setValue(getBigDecimalValue().subtract(value));
	}
	
	/**
	 * @param value
	 */
	public void subtract(final BigInteger value) {
	
		setValue(getBigIntegerValue().subtract(value));
	}
	
	/**
	 * @param value
	 */
	public void subtract(final Double value) {
	
		setValue(getDoubleValue() - value);
	}
	
	/**
	 * @param value
	 */
	public void subtract(final Float value) {
	
		setValue(getFloatValue() - value);
	}
	
	/**
	 * @param value
	 */
	public void subtract(final Integer value) {
	
		setValue(getIntValue() - value);
	}
	
	/**
	 * @param value
	 */
	public void subtract(final Long value) {
	
		setValue(getLongValue() - value);
	}
	
	/**
	 * @param value
	 */
	public void subtract(final Short value) {
	
		setValue(getShortValue() - value);
	}
	
	/**
	 * @param value
	 */
	public void sum(final BigDecimal value) {
	
		setValue(getBigDecimalValue().add(value));
	}
	
	/**
	 * @param value
	 */
	public void sum(final BigInteger value) {
	
		setValue(getBigIntegerValue().add(value));
	}
	
	/**
	 * @param value
	 */
	public void sum(final Double value) {
	
		setValue(getDoubleValue() + value);
	}
	
	/**
	 * @param value
	 */
	public void sum(final Float value) {
	
		setValue(getFloatValue() + value);
	}
	
	/**
	 * @param value
	 */
	public void sum(final Integer value) {
	
		setValue(getIntValue() + value);
	}
	
	/**
	 * @param value
	 */
	public void sum(final Long value) {
	
		setValue(getLongValue() + value);
	}
	
	/**
	 * @param value
	 */
	public void sum(final Short value) {
	
		setValue(getShortValue() + value);
	}
}
